home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / os2 / plnk081.zip / pilot-link.0.8.1 / iambicexample.cc < prev    next >
C/C++ Source or Header  |  1997-05-23  |  9KB  |  267 lines

  1.  
  2. #include "pi-source.h"
  3. #include <stdio.h>
  4. #include <math.h>
  5. #include <iostream.h>
  6. #include <sys/types.h>
  7. #include <stdlib.h>
  8. #include "pi-file.h"
  9. #include "pi-iambicExpense.h"
  10.  
  11. const char *const DEFAULT_FILE = "/afs/pdx/u/g/r/grosch/.xusrpilot/backup/ExpenseDB-IAMBIC.pdb";
  12.  
  13. static char *months[] = {
  14.      "January", "February", "March", "April", "May", "June", "July",
  15.      "August", "September", "October", "November", "December"
  16. };
  17.  
  18. static char *commify(const double amount)
  19. {
  20.      static char buf[30], srcBuf[30];
  21.      char *dst, *src;
  22.      int i;
  23.      
  24.      (void) sprintf(srcBuf, "%.2f", amount);
  25.      
  26.      dst = &buf[sizeof(buf) - 1];
  27.      src = &srcBuf[strlen(srcBuf) - 1];
  28.      
  29.      /* Copy in the cents and the decimal*/
  30.      *dst-- = '\0';
  31.      *dst-- = *src--;
  32.      *dst-- = *src--;
  33.      *dst-- = *src--;
  34.      
  35.      /* Now copy the dollars, adding in commas where necessary */
  36.      for (i = 1; src >= srcBuf; src--, i++) {
  37.           *dst-- = *src;
  38.       
  39.           if (i % 3 == 0 && src != srcBuf)
  40.                *dst-- = ',';
  41.      }
  42.      
  43.      *dst = '$';
  44.      
  45.      return dst;
  46. }
  47.  
  48.      
  49. struct iambicExpenseTypes_t {
  50.      char *name;
  51.      double total;
  52.      iambicExpenseTypes_t *next;
  53.      iambicExpenseTypes_t() : name(NULL), total(0.0), next(NULL) {};
  54. } *typesHead;
  55.  
  56. static void generateHeader(const int idx) 
  57. {
  58.      cout << "%!PS-Adobe-1.0" << endl
  59.       << "%%DocumentFonts: Helvetica" << endl
  60.       << "%%Title: XPilot Expenditures Report" << endl
  61.       << "%%Creator: XPilot 1.0" << endl
  62.       << "%%CreationDate: Fri Feb 28 13:48:43 1997" << endl
  63.       << "%%Pages: 1" << endl
  64.       << "%%EndComments" << endl
  65.       << "" << endl
  66.       << "/useColor true def      % Change this to false for black/white output" << endl
  67.       << "" << endl
  68.       << "/labelps 20 def        % The point size to use for pie chart labels" << endl
  69.       << "/titleps 50 def        % The point size to use the the title of the page" << endl
  70.       << "/titleYpos 720 def      % The y position to start the title at" << endl
  71.       << "" << endl
  72.       << "/colors [" << endl
  73.       << " [0 0 0] [0 1 1] [1 0 1] [1 1 0] [1 1 1] [0 0 .5] [0 .5 0] [0 .5 .5] [.5 0 0]" << endl
  74.       << " [.5 0 .5] [.5 .2 0] [1 .5 .5] [0 0 1] [0 1 0] [1 0 0]" << endl
  75.       << "] def" << endl
  76.       << "" << endl
  77.       << "/setColor {" << endl
  78.       << " /newLen colors length 1 sub def /curColor colors newLen get def" << endl
  79.       << " /colors colors aload pop pop newLen array astore def" << endl
  80.       << " curColor aload pop setrgbcolor % Leave this color on the stack" << endl
  81.       << "} def" << endl
  82.       << "" << endl
  83.       << "/printTitle { 0 0 moveto title show } def" << endl
  84.       << "" << endl
  85.       << "/DrawTitle {" << endl
  86.       << " gsave /Helvetica findfont titleps scalefont setfont " << endl
  87.       << " 306 title stringwidth pop 2 div sub titleYpos translate useColor " << endl
  88.       << " { .65 0 .90 setrgbcolor .50 -.05 0 { pop printTitle 1 -.5 " << endl
  89.       << " translate } for } { .95 -.05 0 { setgray printTitle 1 -.5 translate }" << endl
  90.       << " for } ifelse 1 setgray printTitle grestore" << endl
  91.       << "} def" << endl
  92.       << "" << endl
  93.       << "/DrawTotals" << endl
  94.       << "{" << endl
  95.       << " /x 36 def" << endl
  96.       << " /y titleYpos titleps sub 30 sub def" << endl
  97.       << "" << endl
  98.       << " newpath /Helvetica findfont labelps scalefont setfont" << endl
  99.       << "" << endl
  100.       << " /labelLength 0 def" << endl
  101.       << " /amountLength 0 def" << endl
  102.       << " dataArray {" << endl
  103.       << "    /elem exch def elem 0 get stringwidth pop /lenLabel exch def " << endl
  104.       << "        lenLabel labelLength gt { /labelLength lenLabel def } if" << endl
  105.       << "    elem 2 get stringwidth pop /lenAmount exch def" << endl
  106.       << "        lenAmount amountLength gt { /amountLength lenAmount def } if" << endl
  107.       << " } forall" << endl
  108.       << " /rightMargin labelLength 30 x lenAmount add add add def" << endl
  109.       << " rightMargin y labelps 2 div add moveto" << endl
  110.       << " /totHeight labelps 5 add dataArray length 1 sub mul def" << endl
  111.       << " /bottom y totHeight sub def" << endl
  112.       << " /totHeight totHeight 2 div def" << endl
  113.       << " /middle y totHeight sub def" << endl
  114.       << " rightMargin 90 add middle lineto" << endl
  115.       << " currentpoint /backtoY exch def /backtoX exch def" << endl
  116.       << " 10 labelps 2 div neg rmoveto " << endl
  117.       << " totalSpent show backtoX backtoY moveto" << endl
  118.       << " rightMargin bottom lineto" << endl
  119.       << " stroke " << endl
  120.       << " dataArray {" << endl
  121.       << "    /elem exch def elem aload pop /total exch def pop /label exch def" << endl
  122.       << "    x y moveto label show rightMargin total stringwidth pop sub y moveto " << endl
  123.       << "    total show /y y labelps sub 5 sub def" << endl
  124.       << " } forall" << endl
  125.       << "} def" << endl
  126.       << "" << endl
  127.       << "/DrawSlice {" << endl
  128.       << "  /grayshade exch def /endangle exch def /startangle exch def /thelabel exch def" << endl
  129.       << "  newpath 0 0 moveto 0 0 radius startangle endangle arc closepath" << endl
  130.       << "  1.415 setmiterlimit gsave useColor {setColor} {grayshade setgray} ifelse " << endl
  131.       << "  fill grestore stroke gsave startangle endangle add 2 div rotate radius 0 " << endl
  132.       << "  translate newpath 0 0 moveto labelps .8 mul 0 lineto stroke labelps 0 " << endl
  133.       << "  translate 0 0 transform grestore itransform /y exch def /x exch def x y " << endl
  134.       << "  moveto x 0 lt { thelabel stringwidth pop neg 0 rmoveto } if y 0 lt { 0 " << endl
  135.       << "  labelps neg rmoveto } if thelabel show" << endl
  136.       << "} def" << endl
  137.       << "" << endl
  138.       << "/findgray {" << endl
  139.       << " /i exch def /n exch def i 2 mod 0 eq { i 2 div n 2 div round add n div }" << endl
  140.       << " { i 1 add 2 div n div } ifelse" << endl
  141.       << "} def" << endl
  142.       << "" << endl
  143.       << "/DrawPieChart {" << endl
  144.       << " /radius 140 def gsave" << endl
  145.       << " 306 radius labelps .8 mul labelps 2 mul add add translate" << endl
  146.       << " /Helvetica findfont labelps scalefont setfont" << endl
  147.       << " /numslices dataArray length def /slicecnt 0 def /curangle 0 def" << endl
  148.       << " dataArray {" << endl
  149.       << "    /slicearray exch def slicearray aload pop /amount exch def" << endl
  150.       << "    /percent exch def /label exch def /perangle percent 360 mul def" << endl
  151.       << "    /slicecnt slicecnt 1 add def label curangle curangle perangle add" << endl
  152.       << "    numslices slicecnt findgray DrawSlice" << endl
  153.       << "    /curangle curangle perangle add def" << endl
  154.       << " } forall grestore" << endl
  155.       << "}def" << endl
  156.       << "" << endl
  157.       << "/doit {" << endl
  158.       << " /saveobj save def" << endl
  159.       << " /totalSpent exch def /dataArray exch def /title exch def " << endl
  160.       << " DrawTitle DrawTotals DrawPieChart" << endl
  161.       << " saveobj restore" << endl
  162.       << "} def" << endl
  163.       << "" << endl
  164.       << "%%EndProlog" << endl
  165.       << "" << endl
  166.       << "% ----------------------------------------------------------------------------" << endl
  167.       << "% This is the end of the procedures.  Data for each page follows" << endl
  168.       << "% ----------------------------------------------------------------------------" << endl
  169.       << "%%Page: 1 1" << endl << "(";
  170.  
  171.      cout << months[idx] << " Expenditures) [" << endl;
  172. }
  173.  
  174. int main(int argc, char **argv) 
  175. {
  176.      pi_file *pf = pi_file_open((char *) DEFAULT_FILE);
  177.      
  178.      if (pf == NULL) {
  179.           perror("pi_file_open");
  180.           return 1;
  181.      }
  182.  
  183.      int month;
  184.      
  185.      if (argc == 2)
  186.       month = atoi(argv[1]) - 1;
  187.      else {
  188.       time_t curTime = time(NULL);
  189.       tm *curDate = localtime(&curTime);
  190.       month = curDate->tm_mon;
  191.      }
  192.      
  193.      int nentries;
  194.      pi_file_get_entries(pf, &nentries);
  195.      
  196.      unsigned char *buf;
  197.      int attrs, cat;
  198.      
  199.      iambicExpense_t expense;
  200.      const char *sptr;
  201.      double exchangeRate, amount, total = 0.0;
  202.      const tm *datePtr;
  203.      iambicExpenseTypes_t *typePtr;
  204.      
  205.      typesHead = new iambicExpenseTypes_t;
  206.      
  207.      for (int entnum = 0; entnum < nentries; entnum++) {
  208.           if (pi_file_read_record(pf, entnum, (void **) &buf, 0,
  209.                                   &attrs, &cat, 0) < 0) {
  210.                cout << "Error reading record number " << entnum << endl;
  211.            continue;
  212.           }
  213.       
  214.           /* Skip deleted records */
  215.           if ((attrs & dlpRecAttrDeleted) || (attrs & dlpRecAttrArchived))
  216.                continue;
  217.  
  218.       expense.unpack(buf);
  219.       
  220.       // We only want to print records from this month
  221.       datePtr = expense.date();
  222.       if (datePtr->tm_mon != month)
  223.            continue;
  224.       
  225.       if ((sptr = expense.type()) == NULL)
  226.            sptr = "Unknown";
  227.       
  228.       amount = expense.amount();
  229.       
  230.       if ((exchangeRate = expense.exchangeRate()) != 1.0)
  231.            amount = floor(exchangeRate * amount * 100.0) / 100.0;
  232.       
  233.       for (typePtr = typesHead->next; typePtr != NULL; typePtr = typePtr->next)
  234.            if (!strcmp(typePtr->name, sptr)) {
  235.             typePtr->total += amount;
  236.             break;
  237.            }
  238.       
  239.       if (typePtr == NULL) {
  240.            typePtr = new iambicExpenseTypes_t;
  241.            typePtr->name = strdup(sptr);
  242.            typePtr->total = amount;
  243.            typePtr->next = typesHead->next;
  244.            typesHead->next = typePtr;
  245.       }
  246.       
  247.       total += amount;
  248.      }
  249.  
  250.      generateHeader(month);
  251.      
  252.      double percent;
  253.      
  254.      for (typePtr = typesHead->next; typePtr != NULL; typePtr = typePtr->next) {
  255.       percent = typePtr->total / total;
  256.       cout << "  [(" << typePtr->name << ") " << percent << " ("
  257.            << commify(typePtr->total) << ")]" << endl;
  258.      }
  259.  
  260.      cout << "] (" << commify(total) << ") doit" << endl << "showpage" << endl;
  261.      cout << "%%Trailer" << endl;
  262.      
  263.      pi_file_close(pf);
  264.      
  265.      return 0;
  266. }
  267.